Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Vec3::slerp #583

Merged
merged 2 commits into from
Dec 21, 2024
Merged

Add Vec3::slerp #583

merged 2 commits into from
Dec 21, 2024

Conversation

tim-blackbird
Copy link
Contributor

Based on GLMs implementation with added logic to handle:

  • Non-normalized vectors
  • Zero length vectors
  • Parallel vectors, both in the same and opposite direction

This makes it identical in behavior to Godot's and Unity's slerp implementations

Notes

  • I wanted to add Vec3::rotate_towards as well making use of slerp, but I noticed that the behavior of Vec2::rotate_towards is different. Vec2::rotate_towards rotates self to be parallel to rhs, it doesn't ever become rhs If they have different lengths - I have updated the docs to reflect this -. A slerp based implementation would behave that way, and having different behavior between Vec2 and Vec3 for the same method would be undesirable.
  • I benchmarked this against Godot's implementation using the infrastructure here and this performs a bit better on my machine (33ns~ vs 36ns~) while also accounting for parallel vectors in the opposite direction which Godot's implementation doesn't do.
  • Is there desire for a more performant alternative method dedicated to normalized vectors?

@bitshifter
Copy link
Owner

Run out of time for tonight, but I did wonder what an example use case for slerping rotation and magnitude is? It's not something that occurred to me. Is that something Unity and Godot implementations do also?

There is some extra cost incurred if we can't assume that the input vectors are length zero and they behave differently to the Quat methods of the same name given we expect Quat to be unit length. Which isn't to say that scale shouldn't be handled, but possibly it is worth having versions that slerp or rotate with and without scale and the scale version is named differently from the Quat methods.

@tim-blackbird
Copy link
Contributor Author

Ran out of time for tonight

Take your time! I'm not in a hurry - even if it may seem that way, haha

Is that something Unity and Godot implementations do also?

Yes, both Unity and Godot interpolate the magnitude in their vector slerp implementations - which does make sense for a lerp in spherical coordinates -, and for the quat slerp implementation they require quaternions to be unit length, like ours.

Unity docs: vector slerp, quat slerp
Godot docs: vector slerp, quat slerp

Unity's and Godot's implementations are likely the most well known implementations - very likely for Bevy's userbase -, and it still handles unit vectors as anyone would expect which makes me think calling this slerp is the right move.

This does run about 25%~ slower compared to the slerp method that assumes the inputs are unit vectors that I have locally. Which is a good reason to have a method - slerp_unit perhaps? - to reach for when the user knows they're only dealing with unit vectors in a hot loop

@bitshifter
Copy link
Owner

I haven't had time to put much more thought into this, I did notice that Unreal doesn't have a method that slerps rotation and magnitude, it just has https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Math/TVector/SlerpNormals and https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Math/TVector/SlerpVectorToDirection (which maintains the magnitude of the input vector).

I would almost be inclined to only add slerp_normals, lerping magnitude in slerp seems like it would be fairly niche, but it could be added if someone wanted that specific functionality.

@bitshifter
Copy link
Owner

I did think of one example where lerping the length might be useful, which is sometimes when dealing with velocity vectors it could be desirable to slerp towards a target velocity. Still, this feels a bit less common to me so I feel like offering a method that just slerps normals would be desirable as well, so people don't need to pay the cost of dealing with length if they don't need it.

@bitshifter bitshifter merged commit 77c55be into bitshifter:main Dec 21, 2024
18 checks passed
@bitshifter
Copy link
Owner

Decided to take this as is, slerp_normals could be added later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants